home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Graphics / NXPlot3d / Source / Plot3DView.m < prev    next >
Text File  |  1994-02-20  |  22KB  |  953 lines

  1. /* Plot3DView.m   Copyright 1992 Steve Ludtke */
  2. /* This view allows the display of 3d functions with real time rotation */
  3.  
  4. #import "Plot3DView.h"
  5. #import "PlotShape.h"
  6. #import "PControl.h"
  7. #import <appkit/appkit.h>
  8. #import <3Dkit/3Dkit.h>
  9. #import <dpsclient/event.h>
  10. #import <dpsclient/psops.h>
  11. #import <stdio.h>
  12. #import <math.h>
  13. #include <libc.h>
  14. #import "Expression.h"
  15. #import "DensView.h"
  16.  
  17. void PSsethel();    /* makes Helvetica current font */
  18.  
  19. #define LRAD 10.0
  20.  
  21. extern id NXApp;
  22.  
  23. float rnd0(float x) { if (x<0) return(ceil(x)); else return floor(x); }
  24.  
  25. @implementation Plot3DView
  26. -initFrame:(NXRect *)myrect
  27. {
  28. int i,j,ddl;
  29. RtPoint fromP = {0,0,6.0}, toP = {0,0,0};
  30. RtPoint lFromP = {5.0,10.0,5.0},lToP = {0,0,0};
  31. RtMatrix mx = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1.0 };
  32. id aShader;
  33. char home[60];
  34.  
  35. [super initFrame:(NXRect *)myrect];
  36.  
  37. [self setBackgroundColor:NX_COLORWHITE];  
  38. [self setDrawBackgroundColor:YES];
  39.  
  40. [self setEyeAt:fromP toward:toP roll:0.0];
  41.  
  42. mx[0][0]=mx[1][1]=mx[2][2]=3.0/fromP[2];
  43. [self setPreTransformMatrix:mx];
  44.   
  45.   aShader=[[N3DShader alloc] init];
  46.   [(N3DShader *)aShader setShader:"matte"];
  47.  
  48.   shape=[[PlotShape alloc] init];
  49.   [(N3DShape *) shape  setShader:aShader];
  50.   [shape scale:-1.0 :1.0 :1.0];
  51.   [[self setWorldShape:shape] free];
  52.  
  53.   ambLight=[[N3DLight alloc] init];
  54.   [ambLight makeAmbientWithIntensity:0.2];
  55.   [self addLight:ambLight];
  56.   ambient=0.2;
  57.  
  58. ltheta=.785;
  59. lchi=-.785;
  60. aLight=[[N3DLight alloc] init];
  61. lFromP[0]= LRAD*sin(lchi)*cos(ltheta);
  62. lFromP[2]= LRAD*cos(lchi)*cos(ltheta);
  63. lFromP[1]= LRAD*sin(ltheta);
  64. [aLight makeDistantFrom:lFromP to:lToP intensity:0.8];
  65. [self addLight:aLight];
  66.  
  67.   Rmode=3;
  68.  
  69. ddl=[Window defaultDepthLimit];
  70. if (ddl==NX_TwoBitGrayDepth||ddl==NX_EightBitGrayDepth) ddl=0;
  71. else ddl=1;
  72.  
  73.  
  74. /* initialize preferences */
  75. for (i=0; i<MAXSETS; i++) {
  76.     pref[i].ndata=0; 
  77.     pref[i].sym= -1;
  78.  
  79.     if (ddl) {
  80.         pref[i].mapcol[0][0]=0.0;
  81.         pref[i].mapcol[0][1]=0.0;
  82.         pref[i].mapcol[0][2]=0.5;
  83.  
  84.         pref[i].mapcol[1][0]=0.7;
  85.         pref[i].mapcol[1][1]=0.0;
  86.         pref[i].mapcol[1][2]=0.7;
  87.  
  88.         pref[i].mapcol[2][0]=1.0;
  89.         pref[i].mapcol[2][1]=0.0;
  90.         pref[i].mapcol[2][2]=0.0;
  91.  
  92.         pref[i].mapcol[3][0]=1.0;
  93.         pref[i].mapcol[3][1]=0.3;
  94.         pref[i].mapcol[3][2]=0.0;
  95.  
  96.         pref[i].mapcol[4][0]=1.0;
  97.         pref[i].mapcol[4][1]=1.0;
  98.         pref[i].mapcol[4][2]=0.0;
  99.     }
  100.     else {
  101.         for (j=0; j<5; j++) {
  102.             pref[i].mapcol[j][0]=pref[i].mapcol[j][1]=pref[i].mapcol[j][2]= 
  103.                 .5+(float)j/10.0;
  104.         }
  105.     }
  106.  
  107.     for (j=0; j<5; j++) pref[i].mapsel[j]=1;
  108.     pref[i].mapmode=1;
  109.  
  110.     pref[i].fileData=pref[i].Sdata=NULL;
  111.     pref[i].expr=[[Expression alloc] init];
  112.     [pref[i].expr parse:"0"];
  113.     pref[i].nx=pref[i].ny=10;
  114. }
  115. /* initial function to display */
  116. pref[0].sym=5;
  117. pref[0].nx=pref[0].ny=40;
  118. [pref[0].expr parse:"cos(sqrt(x^2+y^2)+2*pi*t)/sqrt((x+a)^2+y^2+1)"];
  119.  
  120. /* start spinning, all angles in radians */
  121. chi=.2;
  122. theta=.433;
  123. /*dchi=0.025;*/
  124. dchi=0.0;
  125. initflag=1;
  126. Rflags=RF_axis+RF_persp;
  127. Omode=0;
  128. aspect=1.0;
  129. [shape setOver:Omode];
  130.  
  131. if (ddl) {
  132.     flagcol[0][0]=flagcol[4][0]=0.0;
  133.     flagcol[0][1]=flagcol[4][1]=0.0;
  134.     flagcol[0][2]=flagcol[4][2]=1.0;
  135.     flagcol[1][0]=flagcol[2][0]=1.0;
  136.     flagcol[1][1]=flagcol[2][1]=1.0;
  137.     flagcol[1][2]=flagcol[2][2]=1.0;
  138.     flagcol[3][0]=0.0;
  139.     flagcol[3][1]=1.0;
  140.     flagcol[3][2]=0.0;
  141. }
  142. else {
  143.     flagcol[0][0]=flagcol[4][0]=0.5;
  144.     flagcol[0][1]=flagcol[4][1]=0.5;
  145.     flagcol[0][2]=flagcol[4][2]=0.5;
  146.     flagcol[1][0]=flagcol[2][0]=1.0;
  147.     flagcol[1][1]=flagcol[2][1]=1.0;
  148.     flagcol[1][2]=flagcol[2][2]=1.0;
  149.     flagcol[3][0]=0.0;
  150.     flagcol[3][1]=0.0;
  151.     flagcol[3][2]=0.0;
  152. }
  153. [shape setFlagColors:flagcol];
  154.  
  155. [[[NXApp printInfo] setVertCentered:YES] setOrientation:NX_PORTRAIT andAdjust:YES];
  156. [[NXApp printInfo] setMarginLeft:0.0 right:0.0 top:0.0 bottom:0.0];
  157. [[NXApp printInfo] setHorizPagination:NX_FITPAGINATION];
  158. [[NXApp printInfo] setVertPagination:NX_FITPAGINATION];
  159.  
  160. timer=(DPSTimedEntry)DPSAddTimedEntry(TIMESTEP,itstime,self,NX_RUNMODALTHRESHOLD);
  161. [self zoom:self];
  162.  
  163. if (getenv("USER")!=NULL) {
  164.     sprintf(home,"/tmp/%s",getenv("USER"));
  165.      mkdir(home,0777);
  166. }
  167.  
  168. return self;
  169. }
  170.  
  171. /* fix the scaling after being resized */
  172. -superviewSizeChanged:(const NXSize *)oldsize
  173. {
  174. [super superviewSizeChanged:oldsize];
  175. [self zoom:self];
  176. return self;
  177. }
  178.  
  179. -free
  180. {
  181. DPSRemoveTimedEntry(timer);
  182. [super free];
  183. return self;
  184. }
  185.  
  186. -drawPS:(NXRect *)myrect :(int)rectCount
  187. {
  188. char s[80],t[20];
  189. int i,n,xyz[61];
  190. float x,y,xpm,ypm,pv[61];
  191. RtPoint pnt[61];
  192.  
  193. if (bounds.size.width<150) return self;
  194. /* display alt and az in upper right corner */
  195. PSsetgray(0.0);
  196. PSsethel();
  197. sprintf(s,"Alt:%6.2f  Az:%6.2f",theta*57.295787,chi*57.295787);
  198. PSmoveto(bounds.size.width-100.0,bounds.size.height-15.0);
  199. PSshow(s);
  200. PSstroke();
  201.  
  202. if (Rflags&RF_labels && Rmode<4) {
  203.     if (chi>(M_PI/2.0)&&chi<(M_PI*1.5)) ypm=1.1;
  204.     else ypm=-1.1;
  205.     if (chi<M_PI) xpm=1.1;
  206.     else xpm=-1.1;
  207.  
  208.     for (n=0,y=Tick0[0],x=Tick00[0]; x<1; y+=Tick1[0],x+=Tick01[0],n++) { 
  209.         if (n>59) n=59;
  210.         pnt[n][0]=x; 
  211.         pnt[n][1]=ypm;
  212.         pnt[n][2]=-1.1; 
  213.         pv[n]=y;
  214.         xyz[n]=0;
  215.     }
  216.     for (y=Tick0[1],x=Tick00[1]; x<1; y+=Tick1[1],x+=Tick01[1],n++) { 
  217.         if (n>59) n=59;
  218.         pnt[n][1]=x; 
  219.         pnt[n][0]=xpm;
  220.         pnt[n][2]=-1.1; 
  221.         pv[n]=y;
  222.         xyz[n]=1;
  223.     }
  224.     for (y=Tick0[2],x=Tick00[2]; x<1; y+=Tick1[2],x+=Tick01[2],n++) { 
  225.         if (n>59) n=59;
  226.         pv[n]=y;
  227.         pnt[n][2]=x; 
  228.         if ((chi>M_PI/4.0&&chi<M_PI*.75)||(chi>M_PI*1.25&&chi<M_PI*1.75))
  229.             { pnt[n][1]=ypm; pnt[n][0]=-xpm; }
  230.         else { pnt[n][1]=-ypm; pnt[n][0]=xpm; }
  231.         xyz[n]=2;
  232.     }
  233.     pnt[n][0]=xpm/1.18; pnt[n][1]=ypm/1.18; pnt[n][2]=-1.0;
  234.  
  235.     [shape convertObjectPoints:pnt count:n+1 toCamera:self];
  236.     x=pnt[n][0];
  237.     for (i=0; i<n; i++) {
  238.         if (i==0|| xyz[i]!=xyz[i-1]) 
  239.             strcpy(t,[[tickpos cellAt:2 :xyz[i]] stringValue]);
  240.         sprintf(s,t,pv[i]);
  241.         if (pnt[i][0]<x) PSmoveto(pnt[i][0]-20.0,pnt[i][1]-5.0);
  242.         else PSmoveto(pnt[i][0],pnt[i][1]-5.0);
  243.         PSshow(s);
  244.     }
  245.     PSstroke();
  246. }
  247.  
  248. return self;
  249. }    
  250.  
  251. /* recalculates and redisplays data */
  252. -zoom:sender
  253. {
  254. float x0,x1,xs,y0,y1,ys,xf,yf,zf;
  255. float z0,z1,x,y,z,zz,T,A,B,C,D;
  256. int i,j=0,k,cm,nc,color[5];
  257. id tmp;
  258.  
  259. T=[[varT cellAt:0 :0] floatValue];
  260. A=[[varT cellAt:1 :0] floatValue];
  261. B=[[varT cellAt:2 :0] floatValue];
  262. C=[[varT cellAt:3 :0] floatValue];
  263. D=[[varT cellAt:4 :0] floatValue];
  264.  
  265. /* calculate minima, maxima and step sizes */
  266. x0=minX;
  267. x1=maxX;
  268. y0=minY;
  269. y1=maxY;
  270.  
  271. xf=(x1-x0)/2.0;
  272. yf=(y1-y0)/2.0;
  273.  
  274. /* make sure there's enough space in the data array */
  275. for (i=0; i<NFN; i++) {
  276.     if (pref[i].sym==-1 || pref[i].fileData!=NULL) continue;
  277.     if (pref[i].ndata!=(pref[i].nx*pref[i].ny)) {
  278.         if (pref[i].ndata!=0) { free(pref[i].data); free(pref[i].color); }
  279.         pref[i].data=malloc(sizeof(Point)*(pref[i].nx*pref[i].ny+2));
  280.         pref[i].color=malloc(sizeof(RtColor)*(pref[i].nx*pref[i].ny+2));
  281.         pref[i].ndata=pref[i].nx*pref[i].ny;
  282.     }
  283. }
  284. z0=MAXFLOAT;
  285. z1= -MAXFLOAT;
  286.  
  287. /* calculate (function mode) or clip (file mode) the data */
  288. /* also finds min/max Z */
  289. for (i=0; i<NFN; i++) {
  290.     if (pref[i].sym==-1) continue;
  291.     tmp=pref[i].expr;
  292.     [tmp setVar:"t" value:T];
  293.     [tmp setVar:"a" value:A];
  294.     [tmp setVar:"b" value:B];
  295.     [tmp setVar:"c" value:C];
  296.     [tmp setVar:"d" value:D];
  297.  
  298. /* FILE MODE */
  299.     if (pref[i].fileData!=NULL) {
  300.         k=0;
  301.         for (j=0; j<pref[i].nfdata; j++) {
  302.             if (pref[i].fileData[j].x>x1||pref[i].fileData[j].x<x0||
  303.                 pref[i].fileData[j].y>y1||pref[i].fileData[j].y<y0) continue;
  304.             pref[i].data[k].x=(pref[i].fileData[j].x-x0)/xf-1.0;
  305.             [tmp setVar:"x" value:pref[i].data[k].x];
  306.             pref[i].data[k].y=(pref[i].fileData[j].y-y0)/yf-1.0;
  307.             [tmp setVar:"y" value:pref[i].data[k].y];
  308.             [tmp setVar:"z" value:pref[i].fileData[j].z];
  309.             pref[i].data[k].z=[tmp resultValue];
  310.             if (pref[i].data[k].z>z1) z1=pref[i].data[k].z;
  311.             if (pref[i].data[k].z<z0) z0=pref[i].data[k].z;
  312.             k++;
  313.         }
  314.         pref[i].ndata=k;
  315.  
  316.         if (pref[i].data[0].y!=pref[i].data[1].y) {
  317.             pref[i].nx=pref[i].ny=(int)floor(sqrt((float)k));
  318.         }
  319.         else {
  320.             for (j=1; j<k; j++) if (pref[i].data[j-1].y!=pref[i].data[j].y) break;
  321.             pref[i].nx=j;
  322.             pref[i].ny=k/j;
  323.         }
  324.     }
  325. /* FUNCTION MODE */
  326.     else {
  327.         xs=(maxX-x0)/(float)(pref[i].nx-1);
  328.         ys=(maxY-y0)/(float)(pref[i].ny-1);    
  329.         x1=maxX+xs/2.0;
  330.         y1=maxY+ys/2.0;
  331.         j=0;
  332.         for (y=y0; y<y1; y+=ys) {
  333.             for (x=x0; x<x1; x+=xs) {
  334.                 pref[i].data[j].x=(x-x0)/xf-1.0;
  335.                 pref[i].data[j].y=(y-y0)/yf-1.0;
  336.                 [tmp setVar:"x" value:x];
  337.                 [tmp setVar:"y" value:y];
  338.                 zz=pref[i].data[j].z=[tmp resultValue];
  339.                 if (zz!=zz || zz<-MAXFLOAT || zz>MAXFLOAT) 
  340.                     zz=pref[i].data[j].z=0;
  341.                 if (zz>z1) z1=zz;
  342.                 if (zz<z0) z0=zz;
  343.                 j++;
  344.             }
  345.         }
  346.     }
  347. }
  348. if (z0==MAXFLOAT) return self;
  349.  
  350. /* BOTH MODES */
  351. if (z1<=z0) { z1=z0+.001; z0-=.001; }
  352. /* allow the controller to override min/max Z */
  353. [controller minmaxZ:&z0 :&z1];
  354.  
  355. /* tick spacing calculations */
  356. if ([autotick intValue]) {
  357.     [self tickCalc:5.0 :x0 :x1 :&Tick0[0] :&Tick1[0]];
  358.     [[tickpos cellAt:0 :0] setFloatValue:Tick1[0]];
  359.     [[tickpos cellAt:1 :0] setFloatValue:Tick0[0]];
  360.     [self tickCalc:5.0 :y0 :y1 :&Tick0[1] :&Tick1[1]];
  361.     [[tickpos cellAt:0 :1] setFloatValue:Tick1[1]];
  362.     [[tickpos cellAt:1 :1] setFloatValue:Tick0[1]];
  363.     [self tickCalc:5.0 :z0 :z1 :&Tick0[2] :&Tick1[2]];
  364.     [[tickpos cellAt:0 :2] setFloatValue:Tick1[2]];
  365.     [[tickpos cellAt:1 :2] setFloatValue:Tick0[2]];
  366. }
  367. else {
  368.     Tick1[0]=[[tickpos cellAt:0 :0] floatValue];
  369.     Tick0[0]=[[tickpos cellAt:1 :0] floatValue];
  370.     Tick1[1]=[[tickpos cellAt:0 :1] floatValue];
  371.     Tick0[1]=[[tickpos cellAt:1 :1] floatValue];
  372.     Tick1[2]=[[tickpos cellAt:0 :2] floatValue];
  373.     Tick0[2]=[[tickpos cellAt:1 :2] floatValue];
  374. }
  375. Tick00[0]=(Tick0[0]-x0)/(x1-x0)*2.0-1.0;
  376. Tick01[0]=Tick1[0]/(x1-x0)*2.0;
  377. Tick00[1]=(Tick0[1]-y0)/(y1-y0)*2.0-1.0;
  378. Tick01[1]=Tick1[1]/(y1-y0)*2.0;
  379. Tick00[2]=(Tick0[2]-z0)/(z1-z0)*2.0-1.0;
  380. Tick01[2]=Tick1[2]/(z1-z0)*2.0;
  381. [shape setTicks:Tick00 :Tick01];
  382.  
  383. zf=(z1-z0)/2.0;
  384. /* scale and clip Z */
  385. for (i=0; i<NFN; i++) {
  386.     if (pref[i].sym==-1) continue;
  387.     
  388.     /* Spherical coordinates */
  389.     if (pref[i].sym==6) {
  390.         if (pref[i].Sdata!=NULL) free(pref[i].Sdata);
  391.         pref[i].Sdata=malloc(sizeof(Point)*pref[i].ndata);
  392.         for (k=0; k<pref[i].ndata; k++) {
  393.             x=(pref[i].data[k].x+1.0)*xf+x0;
  394.             y=(pref[i].data[k].y+1.0)*yf+y0;
  395.             if (fabs(z0)>fabs(z1)) z=pref[i].data[k].z/fabs(z0);
  396.             else z=pref[i].data[k].z/fabs(z1);
  397.             if (z>1.0) z=1.0;
  398.             if (z<-1.0) z=-1.0;
  399.             pref[i].Sdata[k].x=z*cos(y)*sin(x);
  400.             pref[i].Sdata[k].y=z*sin(y)*sin(x);
  401.             pref[i].Sdata[k].z=z*cos(x);
  402.         }
  403.     }
  404.  
  405.     /* color info */
  406.     cm=pref[i].mapmode;
  407.     for (j=k=0; j<5; j++) if (pref[i].mapsel[j]) { color[k]=j; k++; }
  408.     nc=k;
  409.     if (nc<2) cm=0;
  410.  
  411.     for (k=0; k<pref[i].ndata; k++) {
  412.         if (pref[i].data[k].z>z1) pref[i].data[k].z=z1;
  413.         if (pref[i].data[k].z<z0) pref[i].data[k].z=z0;
  414.         z=pref[i].data[k].z=(pref[i].data[k].z-z0)/zf-1.0;
  415.         if (cm==1) {
  416.             j=floor((z+1.0)/2.00001*(float)(nc-1));
  417.             z=(z+1.0)/2.0*(float)(nc-1)-(float)j;
  418.             pref[i].color[k][0]=z*pref[i].mapcol[color[j+1]][0]+
  419.                 (1.0-z)*pref[i].mapcol[color[j]][0];
  420.             pref[i].color[k][1]=z*pref[i].mapcol[color[j+1]][1]+
  421.                 (1.0-z)*pref[i].mapcol[color[j]][1];
  422.             pref[i].color[k][2]=z*pref[i].mapcol[color[j+1]][2]+
  423.                 (1.0-z)*pref[i].mapcol[color[j]][2];
  424.         }
  425.     }
  426. }
  427.  
  428. /* display 3d plot */
  429. [shape setData:pref :Rmode :Rflags];
  430. [shape setAng:theta :chi :aspect :ambient];
  431. [self display];
  432. /* display density plot */
  433. [controller updDen:Tick00 :Tick01];
  434. return self;
  435. }
  436.  
  437. /* obvious */
  438. -setAng:(float)alt :(float)az
  439. {
  440. theta=alt;
  441. chi=az;
  442. return self;
  443. }
  444.  
  445. /* allows spinning and zooming with the mouse */
  446. -mouseDown:(NXEvent *)oevent 
  447. {
  448. int oldMask,loop=1;
  449. float ix=0,iy=0,ix2=0,iy2=0;
  450. NXEvent *event,evs;
  451. long tm,tm2;
  452.  
  453. evs=*oevent;
  454. oevent=&evs;
  455. [self convertPoint:&oevent->location fromView:nil];
  456. oevent->location.x=oevent->location.x/bounds.size.width*2.0-1.0;
  457. oevent->location.y=oevent->location.y/bounds.size.height*2.0-1.0;
  458. ix2=ix=oevent->location.x;
  459. iy2=iy=oevent->location.y;
  460. tm2=tm=oevent->time;
  461.  
  462. oldMask = [window addToEventMask:NX_LMOUSEDRAGGEDMASK];
  463.  
  464. while (loop) {
  465.     event = [NXApp getNextEvent:(NX_LMOUSEUPMASK | NX_LMOUSEDRAGGEDMASK)];
  466.     [self convertPoint:&event->location fromView:nil];
  467.     event->location.x=event->location.x/bounds.size.width*2.0-1.0;
  468.     event->location.y=event->location.y/bounds.size.height*2.0-1.0;
  469.  
  470.         switch (event->type) {
  471.         case NX_LMOUSEUP:
  472.                 loop = 0;
  473.                 dchi=-(event->location.x-ix2)/(float)(event->time-tm2)*15.0;
  474.                 if (fabs(dchi)<.004) dchi=0.0;
  475.                 [shape setAng:theta :chi :aspect :ambient];
  476.                 [self display];
  477.             break;
  478.         case NX_LMOUSEDRAGGED:
  479.             theta-=(event->location.y-iy)*3.0;
  480.             chi-=(event->location.x-ix)*4.0;
  481.             if (theta>M_PI/2.0) theta=M_PI/2.0;
  482.             if (theta<-M_PI/2.0) theta=-M_PI/2.0;
  483.             while (chi>2.0*M_PI) chi-=2.0*M_PI;
  484.             while (chi<0.0) chi+=2.0*M_PI;
  485.             ix2=ix;
  486.             iy2=iy;
  487.             tm2=tm;
  488.             ix=event->location.x;
  489.             iy=event->location.y;
  490.             tm=event->time;
  491.             [shape setAng:theta :chi :aspect :ambient];
  492.             [self display];
  493.             break;
  494.         default:
  495.             break;
  496.         }
  497. }
  498. [window setEventMask:oldMask];
  499. return self;
  500. }
  501.  
  502. /* function called by timer */
  503. void itstime(DPSTimedEntry entry,double now,id call)
  504. {
  505. [call step];
  506. return;
  507. }
  508.  
  509. /* do one time step */
  510. -step
  511. {
  512. if (initflag) { 
  513.     /* first time, do initialization stuff */
  514.     if (controller==nil) return self;
  515.     [controller startup:pref];
  516.     [self setSurfaceTypeForAll:N3D_SmoothSolids chooseHider:YES];
  517.     [self zoom:self];
  518.     initflag=0; 
  519. }
  520. if (dchi==0.0) return self;
  521. chi+=dchi;
  522. while (chi>2.0*M_PI) chi-=2.0*M_PI;
  523. while (chi<0.0) chi+=2.0*M_PI;
  524. [shape setAng:theta :chi :aspect :ambient];
  525. [self display];
  526. return self;
  527. }
  528.  
  529. -tickCalc:(float)n :(float)x0 :(float)x1 :(float *)min :(float *)spa
  530. {
  531. float s,e;
  532.  
  533. s=(x1-x0)/n;
  534. e=floor(log10(s));
  535. if (s/pow(10.0,e)<3.0) s=floor(s/pow(10.0,e-1.0))*pow(10.0,e-1.0);
  536. else s=floor(s/pow(10.0,e))*pow(10.0,e);
  537. *min=(floor(x0/s)+1.0)*(s);
  538. *spa=s;
  539. return self;
  540. }
  541.  
  542. /* new min/max values */
  543. -zoomTo:(float)minx :(float)miny :(float)maxx :(float)maxy
  544. {
  545. minX=minx;
  546. minY=miny;
  547. maxX=maxx;
  548. maxY=maxy;
  549. return self;
  550. }
  551.  
  552. -(int)acceptsFirstMouse { return (YES); }
  553.  
  554. -setcontroller:con 
  555. {
  556. controller=con;
  557. return self;
  558. }
  559.  
  560. /* allow user to pause spinning */
  561. -togFreeze:sender
  562. {
  563. static float Tdchi;
  564.  
  565. if ([sender intValue]) {
  566.     Tdchi=dchi;
  567.     dchi=0.0;
  568.     return self;
  569. }
  570. dchi=Tdchi;
  571. return self;
  572. }
  573.  
  574. - renderSelf:(RtToken)context
  575. {
  576.  
  577. return self;
  578. }
  579.  
  580. -makeSMap:sender
  581. {
  582. FILE *out;
  583. char home[60],s[80];
  584. id image,rep;
  585. NXSize size = { 400.0,400.0 };
  586. NXStream *stream;
  587. float xs,ys,x,y,xpm,ypm,fs;
  588. int r;
  589.  
  590. sprintf(home,"/tmp/%s",getenv("USER"));
  591. if (getenv("USER")==NULL) strcpy(home,"/tmp"); 
  592.  
  593. /* write maps for axis labels */
  594. if (Rflags&RF_labels) {
  595.     [window setTitle:"Generating Axis Label Maps"];
  596.  
  597.     if (chi>(M_PI/2.0)&&chi<(M_PI*1.5)) ypm=1.0;
  598.     else ypm=-1.0;
  599.     if (chi<M_PI) xpm=1.0;
  600.     else xpm=-1.0;
  601.  
  602.     r=floor(chi/M_PI*4.0);
  603.  
  604.     image=[[NXImage alloc] initSize:&size];
  605.     [image setCacheDepthBounded:NO];
  606.     [image useCacheWithDepth:NX_TwentyFourBitRGBDepth];
  607.     rep=[image lastRepresentation];
  608.     [rep setAlpha:NO];
  609.     [rep setNumColors:3];
  610.     [image lockFocus];
  611.     PSselectfont("Helvetica-Bold",fs=[fontSize floatValue]);
  612.     PSsetrgbcolor(1.0,.95,1.0);
  613.     PSmoveto(0,0);
  614.     PSlineto(1.0,1.0);
  615.     PSstroke();
  616.  
  617.     PSsetrgbcolor(0,0,0);
  618.     strcpy(s,[[axisTitle cellAt:0 :0] stringValue]);
  619.     PSstringwidth(s,&xs,&ys);
  620.     PSmoveto((size.width-xs)/2.0,size.height/4.0-fs*2.0-10.0);
  621.     PSshow(s);
  622.     for (y=Tick0[0],x=Tick00[0]; x<1; y+=Tick1[0],x+=Tick01[0]) { 
  623.         sprintf(s,[[tickpos cellAt:2 :0] stringValue],y);
  624.         PSstringwidth(s,&xs,&ys);
  625.         if (ypm<0)
  626.             PSmoveto((x+1.0)*size.width/2.0-xs/2.0-1.0,size.height/4.0-fs-6.0);
  627.         else PSmoveto(size.width*(1.0-x)/2.0-xs/2.0-1.0,size.height/4.0-fs-6.0);
  628.         PSshow(s);
  629.     }
  630.     PSstroke();
  631.  
  632.     strcpy(s,[[axisTitle cellAt:1 :0] stringValue]);
  633.     PSstringwidth(s,&xs,&ys);
  634.     PSmoveto((size.width-xs)/2.0,size.height/2.0-fs*2.0-10.0);
  635.     PSshow(s);
  636.     for (y=Tick0[1],x=Tick00[1]; x<1; y+=Tick1[1],x+=Tick01[1]) { 
  637.         sprintf(s,[[tickpos cellAt:2 :1] stringValue],y);
  638.         PSstringwidth(s,&xs,&ys);
  639.         if (xpm>0) 
  640.             PSmoveto((x+1.0)*size.width/2.0-xs/2.0-1.0,size.height/2.0-fs-6.0);
  641.         else PSmoveto(size.width*(1.0-x)/2.0-xs/2.0-1.0,size.height/2.0-fs-6.0);
  642.         PSshow(s);
  643.     }
  644.     PSstroke();
  645.  
  646.     PSgsave();
  647.     strcpy(s,[[axisTitle cellAt:2 :0] stringValue]);
  648.     PSstringwidth(s,&xs,&ys);
  649.     PStranslate(size.width/2.0,size.height*3.0/4.0);
  650.     if (r%2==1) PSrotate(180.0);
  651.     PSmoveto(-xs/2.0,0.0);
  652.     PSshow(s);
  653.     PSstroke();
  654.     PSgrestore();
  655.     PSgsave();
  656.     PSrotate(90.0);
  657.     PStranslate(size.height/2.0,-size.width);
  658.     for (y=Tick0[2],x=Tick00[2]; x<1; y+=Tick1[2],x+=Tick01[2]) { 
  659.         sprintf(s,[[tickpos cellAt:2 :2] stringValue],y);
  660.         PSstringwidth(s,&xs,&ys);
  661.         if (r%2==1)
  662.             PSmoveto(size.height/2.0-xs-2.0,(x+1.0)*(size.width)/2.0-8.0);
  663.         else PSmoveto(8.0,(x+1.0)*(size.width)/2.0-8.0);
  664.         PSshow(s);
  665.     }
  666.     PSstroke();
  667.     PSgrestore();
  668.     [image unlockFocus];
  669.     stream=NXOpenMemory(NULL,0,NX_WRITEONLY);
  670.     [image writeTIFF:stream];
  671.     sprintf(s,"%s/plot3dxyz.tiff",home);
  672.     NXSaveToFile(stream,s);
  673.     NXClose(stream);
  674.     [image free];
  675.  
  676.     sprintf(s,"%s/plot3d.rib",home);
  677.     out=fopen(s,"w");
  678.     fprintf(out,"MakeTexture \"%s/plot3dxyz.tiff\" \"%s/plot3dxyz.tx\" \"clamp\" \"black\" \"box\" 1 1\n",home,home);
  679.     fclose(out);
  680.     sprintf(s,"/usr/prman/prman %s/plot3d.rib",home);
  681.     system(s);
  682.     [window setTitle:"3D"];
  683. }
  684.  
  685. if (Omode==0||Omode==OVER_csurf) return self;
  686. [window setTitle:"Generating Surface Map"];
  687.  
  688. /* make map of contour/density plot */
  689. [controller dumpContour];
  690. sprintf(s,"%s/plot3d.rib",home);
  691. out=fopen(s,"w");
  692. fprintf(out,"MakeTexture \"%s/plot3d.tiff\" \"%s/plot3d.tx\" \"black\" \"black\" \"gaussian\" 1.8 1.8\n",home,home);
  693. fclose(out);
  694. sprintf(s,"/usr/prman/prman %s/plot3d.rib",home);
  695. system(s);
  696. [window setTitle:"3D"];
  697. return self;
  698. }
  699.  
  700. - dumpRib:sender
  701. {
  702.   static id savePanel=nil;
  703.   NXStream *ts;
  704.   char buf[MAXPATHLEN+1];
  705.  
  706.   if (!savePanel) {
  707.     savePanel=[SavePanel new];
  708.     [savePanel setRequiredFileType:"rib"];
  709.   }
  710.  
  711.   Rmode+=4;
  712.   [shape setData:pref :Rmode :Rflags];
  713.  
  714.   if([savePanel runModal]){
  715.       [self makeSMap:self];
  716.     ts=NXOpenMemory(NULL, 0, NX_WRITEONLY);
  717.     strcpy(buf, [savePanel filename]);
  718.     strrchr(buf,'.')[0]='\0';
  719.     NXPrintf(ts, "Display \"%s.tiff\" \"file\" \"rgba\"\n", buf);
  720.     [self copyRIBCode:ts];
  721.     NXSaveToFile(ts, [savePanel filename]);
  722.     NXCloseMemory(ts,NX_FREEBUFFER);
  723.   }
  724.  
  725.   Rmode-=4;
  726.   [shape setData:pref :Rmode :Rflags];
  727. return self;
  728. }
  729.  
  730. -PRTiff:sender
  731. {
  732. static id savePanel=nil;
  733.  
  734. if (!savePanel) {
  735.     savePanel=[SavePanel new];
  736.     [savePanel setRequiredFileType:"tiff"];
  737. }
  738.  
  739. if([savePanel runModal]) [self renderTIFF:[savePanel filename]];
  740.  
  741. return self;
  742. }
  743.  
  744. - renderTIFF:(char *)fsp
  745. {
  746. NXStream *ts;
  747. char buf[MAXPATHLEN+1];
  748. char home[60];
  749.  
  750. sprintf(home,"/tmp/%s",getenv("USER"));
  751. if (getenv("USER")==NULL) strcpy(home,"/tmp"); 
  752.  
  753.  
  754. Rmode+=4;
  755. [shape setData:pref :Rmode :Rflags];
  756.  
  757. [self makeSMap:self];
  758. [window setTitle:"Rendering TIFF"];
  759. ts=NXOpenMemory(NULL, 0, NX_WRITEONLY);
  760. NXPrintf(ts, "Display \"%s\" \"file\" \"rgba\"\n", fsp);
  761. [self copyRIBCode:ts];
  762. sprintf(buf,"%s/plot3dp.rib",home);
  763. NXSaveToFile(ts, buf);
  764. NXCloseMemory(ts,NX_FREEBUFFER);
  765.  
  766.  
  767. [shape setData:pref :Rmode :Rflags];
  768. Rmode-=4;
  769.  
  770. sprintf(buf,"/usr/prman/prman %s/plot3dp.rib",home);
  771. system(buf);
  772.  
  773. [window setTitle:"3D"];
  774.  
  775. return self;
  776. }
  777.  
  778. - setAmbLight:sender
  779. {
  780. [ambLight setIntensity:ambient=[sender floatValue]];
  781. [self display];
  782. return self;
  783. }
  784.  
  785. - setLight:sender
  786. {
  787. [aLight setIntensity:[sender floatValue]];
  788. [self display];
  789. return self;
  790. }
  791.  
  792. -setLightX:sender
  793. {
  794. RtPoint from;
  795. lchi= -[sender floatValue];
  796. from[0]= LRAD*sin(lchi)*cos(ltheta);
  797. from[2]= LRAD*cos(lchi)*cos(ltheta);
  798. from[1]= LRAD*sin(ltheta);
  799. [aLight setFrom:from];
  800. [self display];
  801. return self;
  802. }
  803.  
  804. -setLightY:sender
  805. {
  806. RtPoint from;
  807. ltheta=[sender floatValue];
  808. from[0]= LRAD*sin(lchi)*cos(ltheta);
  809. from[2]= LRAD*cos(lchi)*cos(ltheta);
  810. from[1]= LRAD*sin(ltheta);
  811. [aLight setFrom:from];
  812. [self display];
  813. return self;
  814. }
  815.  
  816. - setMode:sender
  817. {
  818. int i;
  819.  
  820. Rmode=i=[sender selectedRow];
  821. switch(i) {
  822. case 0:
  823.  [self setSurfaceTypeForAll:N3D_PointCloud chooseHider:YES];
  824.  [window setDepthLimit:NX_TwoBitGrayDepth];
  825. break;
  826. case 1:
  827.  [self setSurfaceTypeForAll:N3D_WireFrame chooseHider:YES];
  828.  [window setDepthLimit:NX_TwoBitGrayDepth];
  829. break;
  830. case 2:
  831.  [self setSurfaceTypeForAll:N3D_FacetedSolids chooseHider:YES];
  832. break;
  833. case 3:
  834.  [self setSurfaceTypeForAll:N3D_SmoothSolids chooseHider:YES];
  835. break;
  836. }
  837. [shape setData:pref :Rmode :Rflags];
  838. [self display];
  839. return self;
  840. }
  841.  
  842. -setOverlay:sender
  843. {
  844. Omode=0;
  845. if ([[sender cellAt:0 :0] intValue]) Omode+=OVER_surf;
  846. if ([[sender cellAt:1 :0] intValue]) Omode+=OVER_csurf;
  847. if ([[sender cellAt:2 :0] intValue]) Omode+=OVER_base;
  848.  
  849. [shape setOver:Omode];
  850. return self;
  851. }
  852.  
  853. -printPSCode:sender
  854. {
  855.  
  856. [self makeSMap:self];
  857. Rmode+=4;
  858. [shape setData:pref :Rmode :Rflags];
  859. [super printPSCode:sender];
  860. Rmode-=4;
  861. [shape setData:pref :Rmode :Rflags];
  862. return self;
  863. }
  864.  
  865. -setFlags:sender
  866. {
  867. Rflags=0;
  868. if ([[flagSel findCellWithTag:0] intValue]) Rflags+=RF_axis;
  869. if ([[flagSel findCellWithTag:1] intValue]) Rflags+=RF_backs;
  870. if ([[flagSel findCellWithTag:2] intValue]) Rflags+=RF_floor;
  871. if ([[flagSel findCellWithTag:3] intValue]) Rflags+=RF_ticks;
  872. if ([[flagSel findCellWithTag:4] intValue]) Rflags+=RF_planes;
  873. if ([[flagSel findCellWithTag:5] intValue]) Rflags+=RF_labels;
  874. [shape setData:pref :Rmode :Rflags];
  875. [self display];
  876. return self;
  877. }
  878.  
  879. -setFlagColor:sender
  880. {
  881. int i;
  882.  
  883. i=[sender tag];
  884. NXConvertColorToRGB([sender color], 
  885.     &flagcol[i][0],&flagcol[i][1],&flagcol[i][2]);
  886. [shape setFlagColors:flagcol];
  887. [self display];
  888. return self;
  889. }
  890.  
  891. -size320:sender
  892. {
  893. [[self window] sizeWindow:325 :204];
  894. return self;
  895. }
  896.  
  897. -setEye:sender
  898. {
  899. RtPoint fromP = {0,0,6.0},toP={0.0,0.0,0.0};
  900. RtMatrix mx = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1.0 };
  901.  
  902. fromP[2]=[sender floatValue];
  903. [self setEyeAt:fromP toward:toP roll:0.0];
  904. mx[0][0]=mx[1][1]=mx[2][2]=3.0/fromP[2];
  905. [self setPreTransformMatrix:mx];
  906. [self display];
  907. return self;
  908. }
  909.  
  910. -setAsp:sender
  911. {
  912. aspect=[sender floatValue];
  913. [shape setAng:theta :chi :aspect :ambient];
  914. [self display];
  915. return self;
  916. }
  917.  
  918. -setProj:sender
  919. {
  920. if ([sender intValue]) {
  921.     [self setProjection:N3D_Perspective];
  922.     Rflags|=RF_persp;
  923.     [self setUsePreTransformMatrix:NO];
  924. }
  925. else {
  926.     [self setProjection:N3D_Orthographic];
  927.     Rflags&=(~RF_persp);
  928.     [self setUsePreTransformMatrix:YES];
  929. }
  930. [self display];
  931. return self;
  932. }
  933.  
  934. -(float)getTheta
  935. {
  936. return(theta);
  937. }
  938.  
  939. -(float)getChi
  940. {
  941. return(chi);
  942. }
  943.  
  944. -aspect11:sender
  945. {
  946. [aspectS setFloatValue:1.0];
  947. aspect=1.0;
  948. [shape setAng:theta :chi :aspect :ambient];
  949. [self display];
  950. return self;
  951. }
  952. @end
  953.